package com.bwie.service.impl;

import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bwie.config.FastFileUtil;
import com.bwie.config.FreemarkerUtil;
import com.bwie.mapper.GoodsMapper;
import com.bwie.mapper.OrderMapper;
import com.bwie.pojo.*;
import com.bwie.service.FeignService;
import com.bwie.service.OrderService;
import com.bwie.utils.OSSFileUtil;
import com.bwie.utils.R;
import com.bwie.vo.EsOrder;
import com.bwie.vo.PageVo;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import freemarker.template.TemplateException;
import jodd.util.StringUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @Title:
 * @BelongProjecet practice2
 * @BelongPackage com.bwie.service.impl
 * @Description:
 * @Copyright 研发一部
 * @Author: Mr.yan
 * @Date: 2024/6/7 10:06
 * @Version V1.0
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private FastFileStorageClient fastFileStorageClient;
    @Autowired
    private OSSFileUtil ossFileUtil;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private FeignService feignService;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private FastFileUtil fastFileUtil;


    @Override
    public R uploadFile(MultipartFile file) {
        try {
            //1.先上传到fastdfs
            String extName = FileNameUtil.extName(file.getOriginalFilename());
            String fullPath = fastFileStorageClient.uploadFile(file.getInputStream(), file.getSize(), extName, null).getFullPath();
            String url = "http://192.168.158.131:8888/"+fullPath;

            //2.同步到oss
            String ossURL = ossFileUtil.uploadFile(file);

            return R.success(url);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public R createIndex() {
        //1.创建索引
        IndexOperations indexOps = elasticsearchRestTemplate.indexOps(EsOrder.class);
        //判断是否存在
        if (indexOps.exists()){
            return R.error(500,"已存在不能重复创建");
        }
        indexOps.create();

        //2.创建映射
        Document mapping = indexOps.createMapping();
        indexOps.putMapping(mapping);

        return R.success();
    }

    @Override
    public R esOrderList(PageVo pageVo) {
        //1.分页
        int pageNum = 0;
        if (pageVo.getPageNum() > 0){
            pageNum = pageVo.getPageNum() -1;
        }
        PageRequest request = PageRequest.of(pageNum, pageVo.getPageSize());

        //2.高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font color='red'>").postTags("</font>").field("orderNumber");


        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //3.根据订单号查询
        if (!StringUtil.isEmpty(pageVo.getOrderNum())){
            boolQueryBuilder.must(
                    QueryBuilders.termQuery("orderNumber",pageVo.getOrderNum())
            );
        }
        //4.根据收货地址查询
        if (!StringUtil.isEmpty(pageVo.getOrderAddress())){
            boolQueryBuilder.must(
                    QueryBuilders.termQuery("shipmentsAddress",pageVo.getOrderAddress())
            );
        }

        //根据订单状态查询
        if (pageVo.getOrderStatus()!=null && pageVo.getOrderStatus()!=0){
            boolQueryBuilder.must(
                    QueryBuilders.matchQuery("orderStatus",pageVo.getOrderStatus())
            );
        }

        //5.根据订单创建时间区间查询
        if(!StringUtil.isEmpty(pageVo.getStartTime()) && !StringUtil.isEmpty(pageVo.getEndTime())){
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("createTime")
                            .format("yyyy-MM-dd HH:mm:ss")
                            .timeZone("GMT+8")
                            .gte(pageVo.getStartTime())
                            .lte(pageVo.getEndTime())
            );
        }

        //6.生产查询条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder)
                .withPageable(request)
                .withHighlightBuilder(highlightBuilder);

        //7.进行查询，获取查询条件
        SearchHits<EsOrder> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), EsOrder.class);

        //获取总数据
        long total = search.getTotalHits();

        ArrayList<EsOrder> orderArrayList = new ArrayList<>();
        for (SearchHit<EsOrder> esOrderSearchHit : search) {
            EsOrder esOrder = esOrderSearchHit.getContent();

            //获取高亮字段
            List<String> orderNumber = esOrderSearchHit.getHighlightField("orderNumber");
            if (orderNumber!=null && orderNumber.size()>0){
                String num = orderNumber.get(0);
                //用高亮字段替换原有字段
                esOrder.setOrderNumber(num);
            }
            orderArrayList.add(esOrder);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("records",orderArrayList);
        map.put("total",total);
        map.put("pageNum",pageNum);
        map.put("pageSize",pageVo.getPageSize());

        return R.success(map);
    }

    @Override
    @Transactional
    public R addOrder(TbOrder tbOrder) {
        try {
            //1.生成订单编号
            String orderNumber = RandomUtil.randomNumbers(8);
            tbOrder.setOrderNumber(orderNumber);
            //2.添加发货方信息
            R r = feignService.addShipments(tbOrder);
            if (r.getCode() !=200){
                return r;
            }
            String shipId = JSON.toJSONString(r.getData());
            Integer shipmentsId = JSON.parseObject(shipId, Integer.class);
            tbOrder.setShipmentsId(shipmentsId);
            //3.添加收货方信息
            R receiveR = feignService.addReceive(tbOrder);
            if (receiveR.getCode() != 200){
                return receiveR;
            }
            String receive_id = JSON.toJSONString(receiveR.getData());
            Integer receiveId = JSON.parseObject(shipId, Integer.class);
            tbOrder.setReceiveId(receiveId);

            //4.创建添加订单的时间
            tbOrder.setCreateTime(new Date());
            //5.添加信息
            orderMapper.insert(tbOrder);

            //6.添加商品信息
            List<TbGoods> goodsList = tbOrder.getTbGoods();
            for (TbGoods tbGoods : goodsList) {
                tbGoods.setOrderId(tbOrder.getId());
                goodsMapper.insert(tbGoods);
            }

            return R.success();
        } catch (Exception e) {
            return R.error(500,"添加失败");
        }
    }

    @Override
    public R orderDetails(Integer id) {
        try {
            //1.通过id查询到数据
            TbOrder tbOrder = orderMapper.selectOne(
                    new QueryWrapper<TbOrder>().lambda().eq(TbOrder::getId, id)
            );

            //2.常见freemaker工具包
            FreemarkerUtil freemarkerUtil = new FreemarkerUtil();

            //3.创建hashmap
            HashMap<String, Object> map = new HashMap<>();
            map.put("order",tbOrder);

            //4.调用freemaker工具包方法
            String index = freemarkerUtil.createHtml(map, "order", "C:\\freemaker\\" + UUID.randomUUID().toString() + ".html");
            String path = fastFileUtil.uploadFile(new File(index));

            return R.success(path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (TemplateException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public R deleteOrder(List<TbOrder> tbOrderList) {
        //循环删除
        for (TbOrder tbOrder : tbOrderList) {
            orderMapper.deleteById(tbOrder);
            //同步删除es
            EsOrder esOrder = new EsOrder();
            BeanUtils.copyProperties(tbOrder,esOrder);
            elasticsearchRestTemplate.delete(esOrder);
        }



        return R.success();
    }

    @Override
    public R addShip(TbOrder tbOrder) {
        //添加ship表
        R r = feignService.addShipments(tbOrder);
        if (r.getCode()!=200){
            return r;
        }
        String shipId = JSON.toJSONString(r.getData());
        Integer shipmentsId = JSON.parseObject(shipId, Integer.class);
        return R.success(shipmentsId);
    }

    @Override
    @Transactional
    public R addPractice(TbOrder tbOrder) {
        try {
            //1.先生成订单唯一标识
            String orderNum = "order-"+RandomUtil.randomNumbers(4);
            tbOrder.setOrderNumber(orderNum);

            //2.通过feign获取发货方id
            R ship = feignService.addShipments(tbOrder);
            if (ship.getCode()!=200){
                return ship;
            }
            String s = JSON.toJSONString(ship.getData());
            Integer tbShipments = JSON.parseObject(s, Integer.class);
            tbOrder.setShipmentsId(tbShipments);

            //3.通过feign获取收货方id
            R receive = feignService.addReceive(tbOrder);
            if (receive.getCode()!=200){
                return receive;
            }
            String ss = JSON.toJSONString(receive.getData());
            Integer tbReceive = JSON.parseObject(ss, Integer.class);
            tbOrder.setReceiveId(tbReceive);

            //订单创建时间
            tbOrder.setCreateTime(new Date());

            //添加订单信息获取订单的主键id
            orderMapper.insert(tbOrder);

            //4.添加商品
            List<TbGoods> tbGoods = tbOrder.getTbGoods();
            for (TbGoods tbGood : tbGoods) {
                tbGood.setOrderId(tbOrder.getId());
                goodsMapper.insert(tbGood);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return R.success();
    }

    @Override
    public R showPhoto() {
        List<TestPhoto> photoList = orderMapper.photoList();
        return R.success(photoList);
    }

    /**
     * @Description: //TODO
     * @Auther: yanxingru
     * @Date: 2024/6/7 10:58
     * @param: 同步数据
     *
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void orderList(){
        //1.从数据中查询到信息
        Date redisDate = null;
        String esKey  = "es-order";
        //判断是否存在改键
        Boolean aBoolean = stringRedisTemplate.hasKey(esKey);
        if (!aBoolean){
            System.out.println("开始全量同步数据");
            List<EsOrder> esOrderList = orderMapper.esOrderList(null);
            for (EsOrder esOrder : esOrderList) {
                //将数据同步到es中
                elasticsearchRestTemplate.save(esOrder);
                redisDate = esOrder.getUpdateTime();
            }
            //存入缓存
            if (redisDate!=null) {
                stringRedisTemplate.opsForValue().set(esKey, redisDate.getTime() + "");
            }
            System.out.println("全量同步结束");
        }else {
            System.out.println("开始增量同步");
            String s = stringRedisTemplate.opsForValue().get(esKey);
            redisDate = new Date(Long.parseLong(s));
            List<EsOrder> esOrderList = orderMapper.esOrderList(redisDate);
            for (EsOrder esOrder : esOrderList) {
                //将数据同步到es中
                elasticsearchRestTemplate.save(esOrder);
                redisDate = esOrder.getUpdateTime();
            }
            //存入缓存
            if (redisDate!=null) {
                stringRedisTemplate.opsForValue().set(esKey, redisDate.getTime() + "");
            }
            System.out.println("增量同步结束");
        }
    }
}
